package com.lancoo.ccas53.arrangecourse.rulecheck;

import cn.hutool.core.collection.CollUtil;
import com.lancoo.ccas53.arrangecourse.common.BinaryUtil;
import com.lancoo.ccas53.arrangecourse.common.StrUtil;
import com.lancoo.ccas53.arrangecourse.entities.BaseRule;
import com.lancoo.ccas53.arrangecourse.entities.ClassHour;
import com.lancoo.ccas53.arrangecourse.entities.TeachingClassUnit;
import com.lancoo.ccas53.arrangecourse.entities.TimeslotRoom;
import org.apache.commons.lang3.StringUtils;

import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Description 无冲突排课的规则检测，最基础的，检测禁排规则和排课教师和学生冲突问题
 * @Author Fortysun
 * @Date 2023/9/5 16:44
 **/
public class NoClashRuleCheck extends RuleCheck implements RuleDecorator{
    //接收父类的规则服务对象
    private RuleService ruleService;
    public NoClashRuleCheck(RuleService ruleService, BaseRule baseRule) {
        this.ruleService = ruleService;
        super.baseRule = baseRule;
    }
    /**
     * 检测是否适合分配：
     * 1、判断是否满足课程分散、集中规则
     * 2、判断是否满足教师分散、集中规则
     * 3、判断是否满足教师单日最大节次安排
     * @param teachingClassUnit 教学班排课单元
     * @param continuousList 连上的教室课时分组信息列表
     * @param classHourMap 课表课时map
     * @return
     */
    @Override
    public Boolean isSuitable(TeachingClassUnit teachingClassUnit,
                              LinkedList<TimeslotRoom> continuousList,
                              ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        //如果上一个增强的规则是符合要求的
        if (ruleService.isSuitable(teachingClassUnit, continuousList, classHourMap)) {
            //进行无冲突排课的规则的检测
            return isNoClashRuleSuitable(teachingClassUnit, continuousList, classHourMap);
        }

        return false;
    }

    /**
     * 无冲突排课的，最基本的规则，是否符合要求
     * @param teachingClassUnit 教学班排课单元
     * @param continuousList 连上的教室课时分组信息列表
     * @param classHourMap 课表课时map
     * @return
     */
    private Boolean isNoClashRuleSuitable(TeachingClassUnit teachingClassUnit,
                      LinkedList<TimeslotRoom> continuousList,
                      ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        //如果连上的教室课时分组列表信息为空，或者没有内容
        if (continuousList == null || continuousList.isEmpty()) {
//            log.error("#ProhibitClashCheck.isSuitable#:分配的教室课时分组信息列表为空~！！");
            return false;
        }

        //获取排课单元的教学班id
        Long teachingClassId = teachingClassUnit.getTeachingClassId();
        //教学班上课的教师id，多个以逗号分隔
        String teacherIds = teachingClassUnit.getTeacherIds();
        //教学班上课的学生id, 多个以逗号分隔
        String studentIds = teachingClassUnit.getStudentIds();
        //生成教学班的行政班Id
        String phyClassId = teachingClassUnit.getPhyClassId();
        //教学班禁排的课时编码字符串，多个以逗号分隔
        String prohibitTimeslots = teachingClassUnit.getProhibitTimeslotCodes();
        String weeks = teachingClassUnit.getClassWeeks();

        for (TimeslotRoom timeslotRoom : continuousList) {
            String timeslotCode = timeslotRoom.getTimeslotCode();
            CopyOnWriteArrayList<ClassHour> classHours = new CopyOnWriteArrayList<>();
            if (CollUtil.isNotEmpty(classHourMap.get(timeslotCode))){
                classHourMap.get(timeslotCode).forEach(o -> {
                    if (BinaryUtil.binaryAnd(o.getTimeslotRoom().getWeeks(),weeks).contains("1")){
                        classHours.add(o);
                    }
                });
            }

            //分组 拆班，不进行行政班检测
            if (!StringUtils.isEmpty(teachingClassUnit.getUniqueShiftSign())
                    || !StringUtils.isEmpty(teachingClassUnit.getSplitClassUuid())){
                phyClassId = "";
            }

            if ((prohibitTimeslots != null && prohibitTimeslots.contains(timeslotCode))//如果属于禁排的课时
                //如果与当前课时，已经分配的课表数据存在冲突
                || isClashes(teachingClassId, teacherIds, studentIds, phyClassId, classHours)
            ) {//如果当前安排，与其他教学班存在排课冲突
                //当前课时分组列表不合适，不能安排
                return false;
            }
        }

        //可以安排
        return true;
    }


}
